﻿using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using PMS.Core.Caching;
using PMS.Core.Configuration.CommonEnumConfigs;
using PMS.Core.Infrastructure;
using PMS.Core.Utils;
using PMS.Data.Entities.Customers;
using PMS.Data.Entities.Messages;
using PMS.Data.Entities.Settings;
using PMS.Services.Authentication;
using PMS.Services.Authentication.Externel;
using PMS.Services.Caching;
using PMS.Services.EntityServices;
using PMS.Services.EntityServices.Common;
using PMS.Services.EntityServices.Customers;
using PMS.Services.EntityServices.Messages;
using PMS.Services.SharedKernel;
using PMS.Services.Utils;
using PMS.Services.Utils.Captcha;
using PMS.Services.Utils.Events;
using PMS.Services.Utils.Security;
using PMS.Web.Factories.Customers;
using PMS.Web.Framework.Controllers;
using PMS.Web.Framework.Models;
using PMS.Web.Framework.Mvc.Filters;
using PMS.Web.Framework.Validators.IllegalWords;
using PMS.Web.Models;
using PMS.Web.Models.Customers;
using PMS.Web.Models.Messages;
using System;
using System.Linq;
using System.Text.RegularExpressions;

namespace PMS.Web.Controllers.WebApi.Customers
{
    public class CustomerWebApi : BaseApiController
    {
        #region Fields
        private readonly CustomerSettings _customerSettings;
        private readonly IWebHelper _webHelper;
        private readonly IWorkContext _workContext;
        private readonly IStoreContext _storeContext;
        private readonly IDateTimeHelper _dateTimeHelper;
        private readonly ICaptchaService _captchaService;
        private readonly ICustomerService _customerService;
        private readonly ICacheKeyService _cacheKeyService;
        private readonly IStaticCacheManager _staticCacheManager;
        private readonly IEventDispatcher _eventDispatcher;
        private readonly IPermissionService _permissionService;
        private readonly IQueuedEmailService _queuedEmailService;
        private readonly ICustomerModelFactory _customerModelFactory;
        private readonly IAuthenticationProvider _authenticationProvider;
        private readonly IOptions<ApiBehaviorOptions> _apiBehaviorOptions;
        private readonly IWorkflowMessageService _workflowMessageService;
        private readonly IGenericAttributeService _genericAttributeService;
        private readonly ICustomerRegistrationService _customerRegistrationService;
        #endregion

        #region Ctor
        public CustomerWebApi(CustomerSettings customerSettings,
            IWebHelper webHelper,
            IWorkContext workContext,
            IStoreContext storeContext,
            IDateTimeHelper dateTimeHelper,
            ICaptchaService captchaService,
            ICustomerService customerService,
            IEventDispatcher eventDispatcher,
            ICacheKeyService cacheKeyService,
            IStaticCacheManager cacheManager,
            IPermissionService permissionService,
            IQueuedEmailService queuedEmailService,
            ICustomerModelFactory customerModelFactory,
            IAuthenticationProvider authenticationProvider,
            IWorkflowMessageService workflowMessageService,
            IOptions<ApiBehaviorOptions> apiBehaviorOptions,
            IGenericAttributeService genericAttributeService,
            ICustomerRegistrationService customerRegistrationService)
        {
            _webHelper = webHelper;
            _workContext = workContext;
            _storeContext = storeContext;
            _dateTimeHelper = dateTimeHelper;
            _captchaService = captchaService;
            _cacheKeyService = cacheKeyService;
            _staticCacheManager = cacheManager;
            _customerService = customerService;
            _eventDispatcher = eventDispatcher;
            _customerSettings = customerSettings;
            _permissionService = permissionService;
            _queuedEmailService = queuedEmailService;
            _apiBehaviorOptions = apiBehaviorOptions;
            _customerModelFactory = customerModelFactory;
            _authenticationProvider = authenticationProvider;
            _workflowMessageService = workflowMessageService;
            _genericAttributeService = genericAttributeService;
            _customerRegistrationService = customerRegistrationService;
        }
        #endregion

        #region Utils
        private bool SecondAdminAccountExists(Customer customer)
        {
            var customers = _customerService.GetAllCustomers(customerRoleIds: new[] { _customerService.GetCustomerRoleByRoleType(RoleType.Administrator).Id });

            return customers.Any(c => c.IsActive && c.Id != customer.Id);
        }

        #endregion

        #region Methods

        #region CustomerRegister
        /// <summary>
        /// 用户注册Api
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        [HttpPost(WebApiRouteConfig.CustomerRegister)]
        public virtual IActionResult RegisterApi([FromBody] RegisterModel model)
        {
            //check whether registration is allowed
            if (_customerSettings.UserRegistrationType == UserRegistrationType.Disabled)
                return RedirectToAction("RegisterDisallowdView", "Customer");

            try
            {
                var customer = _workContext.CurrentCustomer;
                if (customer != null)
                    throw new PMSException(ApiResponseMessages.CustomerAlreadyLoggin, SystemLogLevel.Warning);

                //若注册方式不需要Email等方式时(如只需要手机号注册)，Email使用默认值，保证Email唯一并不空
                customer = new Customer
                {
                    Email = model.EmailEnabled ? model.Email : $"{model.Mobile}@current-store-name.com",
                    Mobile = model.Mobile,
                    LoginName = model.LoginnameEnabled ? model.Loginname : $"customer_{model.Mobile}",
                    NickName = model.NicknameEnabled ? model.Nickname : model.Mobile,
                    HasShoppingCartItems = false,
                    RequireChangingPwd = false,
                    FailedLoginAttempts = 0,
                    CannotLoginUntilDateUtc = null,
                    IsActive = true,
                    IsDeleted = false,
                    LastActivityTimeUtc = DateTime.UtcNow,
                    CreatedOnTimeUtc = DateTime.UtcNow,
                    UpdatedOnTimeUtc = DateTime.UtcNow,
                    LastLoginTimeUtc = DateTime.UtcNow,
                    LastLoginIpAddress = _webHelper.GetCurrentIpAddress(),
                    RegisteredInStoreId = _storeContext.CurrentStore.Id
                };
                var registrationRequest = new CustomerRegistrationRequest(customer,
                    model.PasswordEnabled ? model.Password : CommonHelper.CreateRandomPasswordWithRandomLength(),
                    _customerSettings.DefaultPasswordFormat,
                    model.PasswordStrongLevel, false, false, true);
                var registrationResult = _customerRegistrationService.RegisterCustomer(registrationRequest);
                if (!registrationResult.Success)
                {
                    //errors
                    throw new PMSException(registrationResult.Errors.FirstOrDefault(), SystemLogLevel.Error);
                }
                string returnUrl = Url.RouteUrl("HomePage");
                switch (_customerSettings.UserRegistrationType)
                {
                    case UserRegistrationType.EmailValidation:
                        return SuccessJson(ApiResponseMessages.CustomerRegistedSuccessAndEmailValidation, new { returnUrl });
                    case UserRegistrationType.AdminApproval:
                        return SuccessJson(ApiResponseMessages.CustomerRegistedSuccessAndAdminAppove, new { returnUrl });
                    case UserRegistrationType.MobileOnly:
                    case UserRegistrationType.Standard:
                    default:
                        return SuccessJson(ApiResponseMessages.CustomerRegistedSuccess, new { returnUrl });
                }
            }
            catch (PMSException pex)
            {
                return pex.LogLevel switch
                {
                    SystemLogLevel.Warning => WarnJson(pex.Message),
                    _ => ErrorJson(pex.Message)
                };
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }
        #endregion

        #region Login/Logout
        /// <summary>
        /// 会员用户/后台管理通用登录功能调用
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        [HttpPost(WebApiRouteConfig.CustomerLogin)]
        public virtual IActionResult LoginApi([FromBody] LoginModel model)
        {
            //validate CAPTCHA
            if (model.DisplayCaptcha)
            {
                var captchaverifyResult = _captchaService.CaptchaVerify(new CaptchaRequest
                {
                    InputAnswer = model.ExtraText,
                    Captcha = model.CaptchaCodeEncrypt
                });
                if (captchaverifyResult.VerifyCode != CaptchaVerifyCode.Success)
                {
                    ModelState.AddModelError(nameof(model.ExtraText), captchaverifyResult.Message);
                    return _apiBehaviorOptions.Value.InvalidModelStateResponseFactory(ControllerContext);
                }
            }

            try
            {
                var loginResult = _customerRegistrationService.ValidateCustomer(model.Account, model.Password);
                var customer = loginResult.customer;
                string returnUrl = Url.RouteUrl("HomePage");
                switch (loginResult.loginResults)
                {
                    case CustomerLoginResults.Successful:
                        {
                            //migrate shopping cart
                            //_shoppingCartService.MigrateShoppingCart(_workContext.CurrentCustomer, customer, true);

                            //sign in new customer
                            _authenticationProvider.AuthServcice.SignIn(customer, model.RememberMe);

                            //raise event      
                            //reserved event for further customer login operates
                            _eventDispatcher.Dispatch(new CustomerLoggedinEvent(customer));

                            //activity log
                            //_customerActivityService.InsertActivity(customer, "PublicStore.Login",
                            //    _localizationService.GetResource("ActivityLog.PublicStore.Login"), customer);
                            //如无指定ReturnUrl则默认跳向首页
                            //后台管理或会员中心登录页可在model中指定跳转链接
                            if (!string.IsNullOrEmpty(model.ReturnUrl) && Url.IsLocalUrl(model.ReturnUrl))
                                returnUrl = model.ReturnUrl;

                            if (returnUrl.Equals(Url.RouteUrl("BackendHome"), StringComparison.OrdinalIgnoreCase))
                            {
                                if (!customer?.IsAdminUser() ?? !customer?.IsAdministrator() ?? false)
                                {
                                    throw new PMSException(ApiResponseMessages.AccountUnAuthorizedWithAdminRoles, SystemLogLevel.Error);
                                }
                            }
                            return SuccessJson(ApiResponseMessages.CustomerLoginSuccess, new { returnUrl });
                        }
                    case CustomerLoginResults.CustomerNotExist:
                        throw new PMSException(ApiResponseMessages.CustomerNotExsits, SystemLogLevel.Error);
                    case CustomerLoginResults.Deleted:
                        throw new PMSException(ApiResponseMessages.CustomerDeleted, SystemLogLevel.Error);
                    case CustomerLoginResults.NotActive:
                        throw new PMSException(ApiResponseMessages.AccountNotActivedYet, SystemLogLevel.Error);
                    case CustomerLoginResults.LoginLimitition:
                        DateTime nextLoginTime = _dateTimeHelper.ConvertToStoreTime(customer.CannotLoginUntilDateUtc.Value);
                        string errorMsg = string.Format(ApiResponseMessages.AccountLoginLimitation, nextLoginTime.ToString("HH:mm"));
                        throw new PMSException(errorMsg, SystemLogLevel.Error);
                    case CustomerLoginResults.LockedOut:
                        throw new PMSException(ApiResponseMessages.AccountLockedOut, SystemLogLevel.Error);
                    case CustomerLoginResults.WrongPassword:
                    default:
                        ModelState.AddModelError(nameof(model.Password), ApiResponseMessages.AccountPasswordNotMatch);
                        return _apiBehaviorOptions.Value.InvalidModelStateResponseFactory(ControllerContext);
                }
            }
            catch (PMSException pex)
            {
                return pex.LogLevel switch
                {
                    SystemLogLevel.Warning => WarnJson(pex.Message),
                    _ => ErrorJson(pex.Message)
                };
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }
        #endregion

        #region CustomerChangePassword
        [AuthorizeCustomer(CustomerAuthorizeType.Guests)]
        [HttpPost(WebApiRouteConfig.CustomerChangePassword)]
        public virtual IActionResult CustomerChangeAccountPwdApi([FromBody] ChangePasswordModel model)
        {
            try
            {
                if (!_customerService.IsRegistered(_workContext.CurrentCustomer))
                    throw new PMSException(ApiResponseMessages.AccountNotActivedYet, SystemLogLevel.Error);
                if (model.Id != _workContext.CurrentCustomer.Id)
                    throw new PMSException(ApiResponseMessages.ModelDataNotCorrect, SystemLogLevel.Error);

                var customer = _workContext.CurrentCustomer;

                if (ModelState.IsValid)
                {
                    var changePasswordRequest = new ChangePasswordRequest(customer.CustomerGuid,
                        true, _customerSettings.DefaultPasswordFormat, model.NewPassword, model.PasswordStrongLevel, model.OldPassword);
                    var changePasswordResult = _customerRegistrationService.ChangePassword(changePasswordRequest);
                    if (changePasswordResult.Success)
                        return SuccessJson(ApiResponseMessages.ModelUpdateSuccess, new { returnUrl = Url.RouteUrl("HomePage") });

                    //errors
                    foreach (var error in changePasswordResult.Errors)
                    {
                        if (string.IsNullOrEmpty(error.Item1))
                            throw new PMSException(error.Item2, SystemLogLevel.Error);
                        else
                            ModelState.AddModelError(error.Item1, error.Item2);
                    }
                    return _apiBehaviorOptions.Value.InvalidModelStateResponseFactory(ControllerContext);
                }
                return ErrorJson("Model Validation Failed");
            }
            catch (PMSException pex)
            {
                return pex.LogLevel switch
                {
                    SystemLogLevel.Warning => WarnJson(pex.Message),
                    _ => ErrorJson(pex.Message)
                };
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }
        #endregion

        #region CustomerPasswordRecover
        [HttpPost(WebApiRouteConfig.CustomerPasswordRecover)]
        public virtual IActionResult PasswordRecoveryApi([FromBody] PasswordRecoveryModel model)
        {
            //validate CAPTCHA
            if (model.DisplayCaptcha)
            {
                var captchaverifyResult = _captchaService.CaptchaVerify(new CaptchaRequest
                {
                    InputAnswer = model.CaptchaAnswer,
                    Captcha = model.EncryptCaptcha
                });
                if (captchaverifyResult.VerifyCode != CaptchaVerifyCode.Success)
                {
                    ModelState.AddModelError(nameof(model.CaptchaAnswer), captchaverifyResult.Message);
                    return _apiBehaviorOptions.Value.InvalidModelStateResponseFactory(ControllerContext);
                }
            }

            try
            {
                if (ModelState.IsValid)
                {
                    Customer customer = model.RecoverByEmail
                        ? _customerService.GetCustomerByEmail(model.Email)
                        : _customerService.GetCustomerByMobile(model.Mobile);
                    if (customer != null && customer.IsActive && !customer.IsDeleted)
                    {
                        if (model.RecoverByEmail)
                        {
                            //save token and current date
                            var passwordRecoveryToken = Guid.NewGuid();
                            _genericAttributeService.SaveAttribute(customer, CustomerDefaultConfigs.PasswordRecoveryTokenAttribute,
                                passwordRecoveryToken.ToString());
                            DateTime? generatedDateTime = DateTime.UtcNow;
                            _genericAttributeService.SaveAttribute(customer,
                                CustomerDefaultConfigs.PasswordRecoveryTokenDateGeneratedAttribute, generatedDateTime);

                            //send email
                            _workflowMessageService.SendCustomerPasswordRecoveryEmail(customer);
                            return SuccessJson(ApiResponseMessages.RecoverByEmailSuccess, new { returnUrl = Url.RouteUrl("HomePage") });
                        }
                        else
                        {
                            throw new PMSException("手机号找回密码服务暂不可用~", SystemLogLevel.Warning);
                        }
                    }
                    else
                        throw new PMSException(ApiResponseMessages.AccountNotAvailable, SystemLogLevel.Error);
                }
                return ErrorJson("Model Validation Failed");
            }
            catch (PMSException pex)
            {
                return pex.LogLevel switch
                {
                    SystemLogLevel.Warning => WarnJson(pex.Message),
                    _ => ErrorJson(pex.Message)
                };
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }

        }

        [HttpPost(WebApiRouteConfig.CustomerPasswordRecoverConfirmPost)]
        public virtual IActionResult PasswordRecoveryConfirmPOST([FromBody] PasswordRecoveryConfirmModel model)
        {
            try
            {
                var customer = _customerService.GetCustomerById(model.Id);
                if (customer == null)
                    throw new PMSException(ApiResponseMessages.AccountNotAvailable, SystemLogLevel.Error);
                //validate token
                if (!_customerService.IsPasswordRecoveryTokenValid(customer, model.PasswordRecoveryToken))
                    throw new PMSException(ApiResponseMessages.PasswordRecoveryTokenNotAvalable, SystemLogLevel.Error);

                //validate token expiration date
                if (_customerService.IsPasswordRecoveryLinkExpired(customer))
                    throw new PMSException(ApiResponseMessages.PasswordRecoveryTokenExpired, SystemLogLevel.Error);

                if (ModelState.IsValid)
                {
                    var response = _customerRegistrationService.ChangePassword(new ChangePasswordRequest(customer.CustomerGuid,
                        false, _customerSettings.DefaultPasswordFormat, model.NewPassword, model.PasswordStrongLevel));
                    if (response.Success)
                    {
                        if (customer.CannotLoginUntilDateUtc.HasValue)
                            customer.CannotLoginUntilDateUtc = null;
                        //Reset customer Login Limitations
                        customer.IsActive = true;
                        customer.FailedLoginAttempts = 0;
                        customer.LastActivityTimeUtc = customer.UpdatedOnTimeUtc = DateTime.UtcNow;
                        _customerService.UpdateCustomer(customer);
                        _genericAttributeService.SaveAttribute(customer, CustomerDefaultConfigs.PasswordRecoveryTokenAttribute, "");
                        _genericAttributeService.SaveAttribute(customer, CustomerDefaultConfigs.PasswordRecoveryTokenDateGeneratedAttribute, "");
                        return SuccessJson(ApiResponseMessages.PasswordRecoveryPostSuccess, new { returnUrl = Url.RouteUrl("HomePage") });
                    }
                    else
                    {
                        //errors
                        foreach (var error in response.Errors)
                        {
                            if (string.IsNullOrEmpty(error.Item1))
                                throw new PMSException(error.Item2, SystemLogLevel.Error);
                            else
                                ModelState.AddModelError(error.Item1, error.Item2);
                        }
                        return _apiBehaviorOptions.Value.InvalidModelStateResponseFactory(ControllerContext);
                    }
                }
                return ErrorJson("Model Validation Failed");
            }
            catch (PMSException pex)
            {
                return pex.LogLevel switch
                {
                    SystemLogLevel.Warning => WarnJson(pex.Message),
                    _ => ErrorJson(pex.Message)
                };
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }
        #endregion

        #region Organize
        [HttpGet(WebApiRouteConfig.LoadOrganizeList)]
        [AuthorizeCustomer(CustomerAuthorizeType.Admin)]
        public virtual IActionResult LoadOrganizeListApi()
        {
            try
            {
                var organizes = _customerService.GetAllOrganizes();
                if (organizes?.Any() ?? false)
                    return SuccessJson("", organizes.Select(o => o.ToModel<OrganizeTreeModel>()).ToList(), true);
                throw new PMSException(string.Format(ApiResponseMessages.EntityNotFound, "组织机构"), SystemLogLevel.Warning);
            }
            catch (PMSException pex)
            {
                return pex.LogLevel switch
                {
                    SystemLogLevel.Warning => WarnJson(pex.Message),
                    _ => ErrorJson(pex.Message)
                };
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }
        #endregion

        #region CustomerChangeAccount
        /// <summary>
        /// 当更改/绑定 用户手机号码时 向新绑定手机号发送短信验证码
        /// 根据绑定模式 新绑定/修改账号 发送短信验证码
        /// 不论新绑定还是修改绑定账号，都只向修改的新账号发送 短信/邮件验证码
        /// </summary>
        /// <param name="accountModel"></param>
        /// <returns></returns>
        [HttpPost(WebApiRouteConfig.SendChangAccountVerifyCodeSMS)]
        [AuthorizeCustomer(CustomerAuthorizeType.Guests)]
        public IActionResult SendCustomVerifyCodeSMSApi([FromBody] BindAccountModel accountModel)
        {
            try
            {
                if (ModelState.IsValid)
                {
                    //validate CAPTCHA
                    if (accountModel.DisplayCaptcha)
                    {
                        var captchaverifyResult = _captchaService.CaptchaVerify(new CaptchaRequest
                        {
                            InputAnswer = accountModel.CaptchaAnswer,
                            Captcha = accountModel.EncryptCaptcha
                        });
                        if (captchaverifyResult.VerifyCode != CaptchaVerifyCode.Success)
                        {
                            ModelState.AddModelError(nameof(accountModel.CaptchaAnswer), captchaverifyResult.Message);
                            return _apiBehaviorOptions.Value.InvalidModelStateResponseFactory(ControllerContext);
                        }
                    }
                    var toCustomer = _workContext.CurrentCustomer;
                    //check account unique
                    Customer checkCustomer = null;
                    if (accountModel.BindMode == AccountBindMode.MobilePhone)
                    {
                        checkCustomer = _customerService.GetCustomerByMobile(accountModel.Mobile);
                    }
                    else if (accountModel.BindMode == AccountBindMode.LoginName)
                    {
                        checkCustomer = _customerService.GetCustomerByUsername(accountModel.LoginName);
                    }
                    else
                    {
                        checkCustomer = null;
                        throw new PMSException("Unsupport AccountChange for sending sms verify code", SystemLogLevel.Error);
                    }
                    if (checkCustomer != null && checkCustomer.Id != accountModel.Id)
                    {
                        ModelState.AddModelError(accountModel.BindMode == AccountBindMode.MobilePhone ? nameof(accountModel.Mobile) : nameof(accountModel.LoginName), ApiResponseMessages.CustomerAlreadyExsits);
                        return _apiBehaviorOptions.Value.InvalidModelStateResponseFactory(ControllerContext);
                    }
                    else if (checkCustomer != null && checkCustomer.Id == accountModel.Id)
                    {
                        ModelState.AddModelError(accountModel.BindMode == AccountBindMode.MobilePhone ? nameof(accountModel.Mobile) : nameof(accountModel.LoginName), ApiResponseMessages.CustomerAccountNotChange);
                        return _apiBehaviorOptions.Value.InvalidModelStateResponseFactory(ControllerContext);
                    } //Only CheckCustomer == null can keep going 

                    if (toCustomer == null || accountModel.Id != toCustomer.Id)
                    {
                        toCustomer = _customerService.GetCustomerById(accountModel.Id);
                    }

                    if (!_workflowMessageService.SendVerifyMessageToCustomer(toCustomer, SMSTemplateNames.CustomerBindAccountTemplateMessage))
                        return ErrorJson(ApiResponseMessages.ShortMessageSendFailed);
                    return SuccessJson(ApiResponseMessages.ShortMessageSendSuccess);
                }
                return ErrorJson(ApiResponseMessages.ArgumentCannotBeNull);
            }
            catch (PMSException pex)
            {
                return pex.LogLevel switch
                {
                    SystemLogLevel.Warning => WarnJson(pex.Message),
                    _ => ErrorJson(pex.Message)
                };
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }

        /// <summary>
        /// 当更改/绑定 用户邮箱账号时 向新绑定邮箱发送短信验证码
        /// 根据绑定模式 新绑定/修改邮箱账号 发送邮箱验证码
        /// 不论新绑定还是修改绑定账号，都只向修改的新账号发送 短信/邮件验证码
        /// </summary>
        /// <param name="accountModel"></param>
        /// <returns></returns>
        [HttpPost(WebApiRouteConfig.SendChangAccountVerifyCodeEmail)]
        [AuthorizeCustomer(CustomerAuthorizeType.Guests)]
        public IActionResult SendChangAccountVerifyCodeEmailApi([FromBody] BindAccountModel accountModel)
        {
            try
            {
                if (ModelState.IsValid)
                {
                    //validate CAPTCHA
                    if (accountModel.DisplayCaptcha)
                    {
                        var captchaverifyResult = _captchaService.CaptchaVerify(new CaptchaRequest
                        {
                            InputAnswer = accountModel.CaptchaAnswer,
                            Captcha = accountModel.EncryptCaptcha
                        });
                        if (captchaverifyResult.VerifyCode != CaptchaVerifyCode.Success)
                        {
                            ModelState.AddModelError(nameof(accountModel.CaptchaAnswer), captchaverifyResult.Message);
                            return _apiBehaviorOptions.Value.InvalidModelStateResponseFactory(ControllerContext);
                        }
                    }
                    var toCustomer = _workContext.CurrentCustomer;
                    if (accountModel.BindMode != AccountBindMode.Email)
                        throw new PMSException("Unsupport change account for sending email verify code", SystemLogLevel.Error);
                    //check account unique
                    Customer checkCustomer = _customerService.GetCustomerByEmail(accountModel.Email);

                    if (checkCustomer != null && checkCustomer.Id != accountModel.Id)
                    {
                        ModelState.AddModelError(nameof(accountModel.Email), ApiResponseMessages.CustomerAlreadyExsits);
                        return _apiBehaviorOptions.Value.InvalidModelStateResponseFactory(ControllerContext);
                    }
                    else if (checkCustomer != null && checkCustomer.Id == accountModel.Id)
                    {
                        ModelState.AddModelError(nameof(accountModel.Email), ApiResponseMessages.CustomerAccountNotChange);
                        return _apiBehaviorOptions.Value.InvalidModelStateResponseFactory(ControllerContext);
                    } //Only CheckCustomer == null can keep going 

                    if (toCustomer == null || accountModel.Id != toCustomer.Id)
                    {
                        toCustomer = _customerService.GetCustomerById(accountModel.Id);
                    }
                    var queuedEmailIds = _workflowMessageService.SendCustomerChangeEmailAccountEmail(toCustomer, accountModel.Email);
                    if((queuedEmailIds?.Count ?? 0) <= 0)
                        return ErrorJson(ApiResponseMessages.EmailServiceNotEnable);
                    return SuccessJson(ApiResponseMessages.CustomEmailSendSuccess);
                }
                return ErrorJson(ApiResponseMessages.ArgumentCannotBeNull);
            }
            catch (PMSException pex)
            {
                return pex.LogLevel switch
                {
                    SystemLogLevel.Warning => WarnJson(pex.Message),
                    _ => ErrorJson(pex.Message)
                };
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }
        /// <summary>
        /// 根据绑定模式 更换当前用户的账号
        /// </summary>
        /// <param name="accountModel"></param>
        /// <returns></returns>
        [HttpPost(WebApiRouteConfig.CustomerChangAccount)]
        [AuthorizeCustomer(CustomerAuthorizeType.Guests)]
        public IActionResult CustomerChangAccountApi([FromBody] BindAccountModel accountModel)
        {
            try
            {
                if (ModelState.IsValid)
                {
                    
                    if(accountModel.BindMode != AccountBindMode.Email)
                    {
                        if (string.IsNullOrEmpty(accountModel.SMSCode))
                        {
                            ModelState.AddModelError(nameof(accountModel.SMSCode), ApiResponseMessages.EmptySMSCode);
                            return _apiBehaviorOptions.Value.InvalidModelStateResponseFactory(ControllerContext);
                        }
                        var verifySMSCodeKey = _cacheKeyService.PrepareKey(CacheKeyConfigs.CustomerSMSVerifyCodeCacheKey, SMSTemplateNames.CustomerBindAccountTemplateMessage, accountModel.Id);
                        var verifyCode = _staticCacheManager.Get<string>(verifySMSCodeKey, () => null);
                        if(string.IsNullOrEmpty(verifyCode) || !verifyCode.Equals(accountModel.SMSCode))
                        {
                            ModelState.AddModelError(nameof(accountModel.SMSCode), ApiResponseMessages.SMSCodeWrong);
                            return _apiBehaviorOptions.Value.InvalidModelStateResponseFactory(ControllerContext);
                        }
                    } 
                    else
                    {
                        if (string.IsNullOrEmpty(accountModel.EmailCode))
                        {
                            ModelState.AddModelError(nameof(accountModel.EmailCode), ApiResponseMessages.EmptyEmailCode);
                            return _apiBehaviorOptions.Value.InvalidModelStateResponseFactory(ControllerContext);
                        }
                        var verifyEmailCodeKey = _cacheKeyService.PrepareKeyForDefaultCache(CacheKeyConfigs.CustomerEmailVerifyCodeCacheKey, EmailMessageTemplateNames.CustomerSendChangeEmailAccountCodeMessage, accountModel.Id);
                        var verifyCode = _staticCacheManager.Get<string>(verifyEmailCodeKey, () => null);
                        if (string.IsNullOrEmpty(verifyCode) || !verifyCode.Equals(accountModel.EmailCode))
                        {
                            ModelState.AddModelError(nameof(accountModel.SMSCode), ApiResponseMessages.EmailVerifyCodeWrong);
                            return _apiBehaviorOptions.Value.InvalidModelStateResponseFactory(ControllerContext);
                        }
                    }

                    var curLoginAccount = _workContext.CurrentCustomer;
                    //check account unique
                    Customer checkCustomer = null;
                    string fieldName = string.Empty;
                    switch (accountModel.BindMode)
                    {
                        case AccountBindMode.Email:
                            fieldName = nameof(accountModel.Email);
                            if (!CommonHelper.IsValidEmail(accountModel.Email))
                            {
                                ModelState.AddModelError(fieldName, ApiResponseMessages.IllegalEmail);
                                return _apiBehaviorOptions.Value.InvalidModelStateResponseFactory(ControllerContext);
                            }
                            curLoginAccount.Email = accountModel.Email;
                            checkCustomer = _customerService.GetCustomerByMobile(accountModel.Email);
                            break;
                        case AccountBindMode.MobilePhone:
                            fieldName = nameof(accountModel.Mobile);
                            if (!CommonHelper.IsValidMobile(accountModel.Mobile))
                            {
                                ModelState.AddModelError(fieldName, ApiResponseMessages.IllegalMobile);
                                return _apiBehaviorOptions.Value.InvalidModelStateResponseFactory(ControllerContext);
                            }
                            curLoginAccount.Mobile = accountModel.Mobile;
                            checkCustomer = _customerService.GetCustomerByMobile(accountModel.Mobile);
                            break;
                        case AccountBindMode.LoginName:
                            fieldName = nameof(accountModel.LoginName);
                            bool validateNewLoginname = true;
                            if (!_customerSettings.UsernameValidationEnabled || string.IsNullOrEmpty(_customerSettings.UsernameValidationRule))
                                validateNewLoginname = false;

                            if (validateNewLoginname)
                            {
                                if (!Regex.IsMatch(accountModel.LoginName, _customerSettings.UsernameValidationRule, RegexOptions.CultureInvariant | RegexOptions.IgnoreCase))
                                {
                                    ModelState.AddModelError(fieldName, _customerSettings.UsernameValidationTips);
                                    return _apiBehaviorOptions.Value.InvalidModelStateResponseFactory(ControllerContext);
                                }
                            }
                            curLoginAccount.LoginName = accountModel.LoginName;
                            checkCustomer = _customerService.GetCustomerByUsername(accountModel.LoginName);
                            break;
                        default:
                            fieldName = string.Empty;
                            break;
                    }
                    if (checkCustomer != null && checkCustomer.Id != accountModel.Id)
                    {
                        ModelState.AddModelError(fieldName, ApiResponseMessages.CustomerAlreadyExsits);
                        return _apiBehaviorOptions.Value.InvalidModelStateResponseFactory(ControllerContext);
                    }
                    else if (checkCustomer != null && checkCustomer.Id == accountModel.Id)
                    {
                        ModelState.AddModelError(fieldName, ApiResponseMessages.CustomerAccountNotChange);
                        return _apiBehaviorOptions.Value.InvalidModelStateResponseFactory(ControllerContext);
                    } //Only CheckCustomer == null can keep going 

                    curLoginAccount.UpdatedOnTimeUtc = DateTime.UtcNow;
                    _customerService.UpdateCustomer(curLoginAccount);
                    //try to resignin customer within new account
                    _authenticationProvider.AuthServcice.SignIn(curLoginAccount, false);
                    //Log ChangeAccount Activity

                    //raise Event for delete cache and remove external authentication account bind
                    _eventDispatcher.Dispatch(new CustomerAccountChangedEvent(curLoginAccount, accountModel.BindMode));

                    return SuccessJson(ApiResponseMessages.CustomerAccountChangeSuccess);
                }
                return ErrorJson(ApiResponseMessages.ArgumentCannotBeNull);
            }
            catch (PMSException pex)
            {
                return pex.LogLevel switch
                {
                    SystemLogLevel.Warning => WarnJson(pex.Message),
                    _ => ErrorJson(pex.Message)
                };
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }
        #endregion

        #region BackendAdminArea

        #region CustomerRoles
        [HttpGet(WebApiRouteConfig.LoadAdminRolesList)]
        [AuthorizeCustomer(CustomerAuthorizeType.Admin)]
        public virtual IActionResult LoadAdminRolesListApi()
        {
            try
            {
                var customerRoles = _customerService.GetAllCustomerRoles();
                RoleType[] adminRoleTypes = new RoleType[] { RoleType.Administrator, RoleType.BackendUser };
                if (customerRoles?.Any() ?? false)
                    return SuccessJson("", customerRoles.Where(r => adminRoleTypes.Contains(r.RoleType))
                                                        .Select(ar => ar.ToModel<AdminRoleModel>())
                                                        .OrderBy(ar => ar.DisplayOrder)
                                                        .ToList());
                throw new PMSException(string.Format(ApiResponseMessages.EntityNotFound, "用户角色"), SystemLogLevel.Warning);
            }
            catch (PMSException pex)
            {
                return pex.LogLevel switch
                {
                    SystemLogLevel.Warning => WarnJson(pex.Message),
                    _ => ErrorJson(pex.Message)
                };
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }
        #endregion

        #region Customer
        [HttpPost(WebApiRouteConfig.LoadCustomerPagedList)]
        [AuthorizeCustomer(CustomerAuthorizeType.Admin)]
        public virtual IActionResult LoadCustomerPagedListApi([FromBody] CustomerSearchModel searchModel)
        {
            try
            {
                searchModel.SearchEmail = CommonHelper.EnsureMaximumLength(searchModel.SearchEmail, 50);
                searchModel.SearchLoginname = CommonHelper.EnsureMaximumLength(searchModel.SearchLoginname, 20);
                searchModel.SearchMobile = CommonHelper.EnsureMaximumLength(searchModel.SearchMobile, 11);
                //prepare model
                bool hideInfo = true;
                //后台登录账号为非系统管理员， 则隐藏用户邮箱信息
                if (_workContext.CurrentCustomer?.IsAdministrator(_customerService) ?? false)
                    hideInfo = false;
                var model = _customerModelFactory.PrepareCustomerListModel(searchModel, hideInfo);
                return SuccessJson("", model);
            }
            catch (PMSException pex)
            {
                return pex.LogLevel switch
                {
                    SystemLogLevel.Warning => WarnJson(pex.Message),
                    _ => ErrorJson(pex.Message)
                };
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }

        [HttpPost(WebApiRouteConfig.LoadOnlineCustomerPagedList)]
        [AuthorizeCustomer(CustomerAuthorizeType.Admin)]
        public virtual IActionResult LoadOnlineCustomerPagedListApi([FromBody] OnlineCustomerSearchModel searchModel)
        {
            try
            {
                //prepare model
                var model = _customerModelFactory.PrepareOnlineCustomerListModel(searchModel);
                return SuccessJson("", model);
            }
            catch (PMSException pex)
            {
                return pex.LogLevel switch
                {
                    SystemLogLevel.Warning => WarnJson(pex.Message),
                    _ => ErrorJson(pex.Message)
                };
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }

        [HttpPost(WebApiRouteConfig.BackendCustomerEdit)]
        [AuthorizeCustomer(CustomerAuthorizeType.Admin)]
        public IActionResult CustomerEditApi([FromBody] CustomerModel editModel)
        {
            try
            {
                var customer = _customerService.GetCustomerById(editModel.Id);

                Action<CustomerModel> saveCustomerExtraAttributes = delegate (CustomerModel model)
                {
                    if (!string.IsNullOrEmpty(model.Gender))
                        _genericAttributeService.SaveAttribute(customer, CustomerDefaultConfigs.GenderAttribute, model.Gender);
                    if (model.DateOfBirth.HasValue)
                        _genericAttributeService.SaveAttribute(customer, CustomerDefaultConfigs.DateOfBirthAttribute, model.DateOfBirth.Value);
                    if (model.DefaultAddress != null && model.DefaultAddress.Count > 0)
                        _genericAttributeService.SaveAttribute(customer, CustomerDefaultConfigs.DefaultAddressIdAttribute, string.Join(",", model.DefaultAddress));
                    if (!string.IsNullOrEmpty(model.DefaultAddressDetail))
                        _genericAttributeService.SaveAttribute(customer, CustomerDefaultConfigs.DefaultAddressDetailAttribute, model.DefaultAddressDetail);
                    if (model.AvatarImage.Id > 0)
                        _genericAttributeService.SaveAttribute(customer, CustomerDefaultConfigs.AvatarPictureIdAttribute, model.AvatarImage.Id);
                };

                if (customer == null || customer.IsDeleted)
                {//新增用户
                    customer = editModel.ToEntity<Customer>();
                    customer.CustomerGuid = Guid.NewGuid();
                    customer.HasShoppingCartItems = false;
                    customer.RegisteredInStoreId = _storeContext.CurrentStore.Id;
                    customer.FailedLoginAttempts = 0;
                    customer.CannotLoginUntilDateUtc = null;
                    customer.IsActive = true;
                    customer.IsDeleted = false;
                    customer.LastActivityTimeUtc = customer.CreatedOnTimeUtc = customer.UpdatedOnTimeUtc = DateTime.UtcNow;
                    customer.LastLoginIpAddress = _workContext.CurrentCustomer.LastLoginIpAddress;
                    var registrationRequest = new CustomerRegistrationRequest(customer, editModel.Password,
                        _customerSettings.DefaultPasswordFormat,
                        editModel.PasswordStrongLevel.Value, true, true, editModel.AllowReSendingOfActivationMessage);//借用 Model.AllowReSendingOfActivationMessage 存储当修改账号密码时，是否发送重置密码邮件
                    var registrationResult = _customerRegistrationService.RegisterCustomer(registrationRequest);
                    if (!registrationResult.Success)
                    {
                        //errors
                        throw new PMSException(registrationResult.Errors.FirstOrDefault(), SystemLogLevel.Error);
                    }

                }
                else //用户信息编辑
                {
                    //用户账号信息只可用户自已账号在资料页面通过手机号绑定、邮箱绑定更改
                    customer.IsActive = editModel.IsActive;
                    customer.IsDeleted = false;
                    customer.UpdatedOnTimeUtc = DateTime.UtcNow;
                    if (customer.IsActive)
                    {
                        customer.FailedLoginAttempts = 0;
                        customer.CannotLoginUntilDateUtc = null;
                    }
                    _customerService.UpdateCustomer(customer);
                    if (editModel.Password.Length > 0)
                    {
                        var changePasswordRequest = new ChangePasswordRequest(customer.CustomerGuid,
                                false, _customerSettings.DefaultPasswordFormat,
                                editModel.Password, editModel.PasswordStrongLevel.Value);
                        var changePasswordResult = _customerRegistrationService.ChangePassword(changePasswordRequest);
                        if (!changePasswordResult.Success)
                        {
                            //errors
                            foreach (var error in changePasswordResult.Errors)
                            {
                                if (string.IsNullOrEmpty(error.Item1))
                                    throw new PMSException(error.Item2, SystemLogLevel.Error);
                                else
                                    ModelState.AddModelError(error.Item1, error.Item2);
                            }
                            return _apiBehaviorOptions.Value.InvalidModelStateResponseFactory(ControllerContext);
                        }
                        if (editModel.AllowReSendingOfActivationMessage)
                        { //借用 Model.AllowReSendingOfActivationMessage 存储当修改账号密码时，是否发送重置密码邮件
                            _workflowMessageService.SendCustomerPasswordChangedEmail(customer, editModel.Password);
                        }
                    }
                }
                saveCustomerExtraAttributes(editModel);
                return SuccessJson((customer == null || customer.IsDeleted) ? ApiResponseMessages.CustomerCreateSuccess : ApiResponseMessages.CustomerEditSuccess);
            }
            catch (PMSException pex)
            {
                return pex.LogLevel switch
                {
                    SystemLogLevel.Warning => WarnJson(pex.Message),
                    _ => ErrorJson(pex.Message)
                };
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }

        /// <summary>
        /// 根据用户ID获取已发送给用户邮件列表数据
        /// </summary>
        /// <param name="CustomerId"></param>
        /// <returns></returns>
        [HttpPost(WebApiRouteConfig.LoadPagedEmailListByCustomer)]
        [AuthorizeCustomer(CustomerAuthorizeType.Admin)]
        public IActionResult LoadPagedEmailListByCustomer([FromBody] CustomerEmailSearchModel searchModel)
        {
            try
            {
                if (searchModel.CustomerId <= 0)
                    searchModel.CustomerId = _workContext.CurrentCustomer?.Id ?? 0;
                var customer = _customerService.GetCustomerById(searchModel.CustomerId);
                if (customer == null)
                    throw new PMSException(string.Format(ApiResponseMessages.EntityNotFound, "用户ID"));
                var queuedEmails = _queuedEmailService.SearchEmails(null, customer.Email, null, null,
                    false, false, 3, false, searchModel.Page - 1, searchModel.PageSize);
                bool hideEmailInfo = true;
                //后台登录账号为非系统管理员， 则隐藏用户邮箱信息
                if (_workContext.CurrentCustomer?.IsAdministrator(_customerService) ?? false)
                    hideEmailInfo = false;

                var listModel = new CustomerListModel().PrepareToGrid(queuedEmails, () =>
                {
                    return queuedEmails.Select(email =>
                    {
                        var model = new CustomerModel();
                        model.Email = hideEmailInfo ? CommonHelper.HideEmailInfo(email.To) : email.To;
                        model.NickName = customer.NickName;
                        //查看列表不加载显示邮件内容
                        model.SendEmail.SendImmediately = false;
                        model.SendEmail.Body = string.Empty;
                        model.SendEmail.Subject = email.Subject;
                        model.SendEmail.SentOnTime = email.IsActive && email.DontSendBeforeDateUtc.HasValue
                                         ? _dateTimeHelper.ConvertToStoreTime(email.DontSendBeforeDateUtc.Value, DateTimeKind.Utc)
                                         : email.SentOnTimeUtc.HasValue ? _dateTimeHelper.ConvertToStoreTime(email.SentOnTimeUtc.Value) : DateTime.Now;
                        model.SendEmail.DontSendBeforeDate = email.DontSendBeforeDateUtc.HasValue
                                                 ? _dateTimeHelper.ConvertToStoreTime(email.DontSendBeforeDateUtc.Value, DateTimeKind.Utc)
                                                 : email.DontSendBeforeDateUtc;
                        model.SendEmail.IsActive = email.IsActive;
                        return model;
                    });
                });
                return SuccessJson("", listModel);
            }
            catch (PMSException pex)
            {
                return pex.LogLevel switch
                {
                    SystemLogLevel.Warning => WarnJson(pex.Message),
                    _ => ErrorJson(pex.Message)
                };
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }

        /// <summary>
        /// 执行向指定用户发送邮件方法调用
        /// CustomerModelValidator 中提交参数做过滤处理，修改方法名时注意同步处理
        /// </summary>
        /// <param name="CustomerId"></param>
        /// <returns></returns>
        [HttpPost(WebApiRouteConfig.SendCustomEmailToCustomer)]
        [AuthorizeCustomer(CustomerAuthorizeType.Admin)]
        public IActionResult SendCustomEmailToCustomerApi([FromBody] CustomerModel emailModel)
        {
            try
            {
                var emailSettings = EngineContext.Current.Resolve<EmailAccountSettings>();
                if (!emailSettings.Enabled)
                    throw new PMSException(ApiResponseMessages.EmailServiceNotEnable, SystemLogLevel.Warning);

                if (emailModel.NickName.Length > 20)
                {
                    ModelState.AddModelError(nameof(emailModel.NickName), "请精简收件人昵称,请勿超过20字符");
                    return _apiBehaviorOptions.Value.InvalidModelStateResponseFactory(ControllerContext);
                }
                if (emailModel.SendEmail.Subject.Length > 100)
                {
                    ModelState.AddModelError(nameof(emailModel.SendEmail.Subject), "请精简邮件标题,请勿超过100字符");
                    return _apiBehaviorOptions.Value.InvalidModelStateResponseFactory(ControllerContext);
                }

                //get CustomerEmail From Query search
                var customer = _customerService.GetCustomerById(emailModel.Id);
                if (customer == null)
                    throw new PMSException(ApiResponseMessages.CustomerNotExsits, SystemLogLevel.Error);
                else if (string.IsNullOrEmpty(customer.Email))
                    throw new PMSException(ApiResponseMessages.CantSendEmailWithEmailUnBind, SystemLogLevel.Warning);
                emailModel.Email = customer.Email;
                var base64EncodedBytes = Convert.FromBase64String(emailModel.SendEmail.Body);
                emailModel.SendEmail.Body = System.Text.Encoding.UTF8.GetString(base64EncodedBytes);

                //IllegalWords Replace
                bool illegalWordsReplaced = false;
                if (IllegalWordsProvider.Instance.IllegalWordsSearch.ContainsAny(emailModel.SendEmail.Body))
                {
                    emailModel.SendEmail.Body = IllegalWordsProvider.Instance.IllegalWordsSearch.Replace(emailModel.SendEmail.Body);
                    illegalWordsReplaced = true;
                }

                var emailAccountService = EngineContext.Current.Resolve<IEmailAccountService>();
                var emailAccount = emailAccountService.GetEmailAccountById(emailSettings.DefaultEmailAccountId);
                if (emailAccount == null)
                    emailAccount = emailAccountService.GetAllEmailAccounts().FirstOrDefault();
                if (emailAccount == null)
                    throw new PMSException(ApiResponseMessages.EmailAccountLoadError, SystemLogLevel.Error);
                var email = new QueuedEmail
                {
                    Priority = QueuedEmailPriority.High,
                    EmailAccountId = emailAccount.Id,
                    FromName = emailAccount.DisplayName,
                    From = emailAccount.Email,
                    ToName = emailModel.NickName,
                    To = emailModel.Email,
                    Subject = emailModel.SendEmail.Subject,
                    Body = emailModel.SendEmail.Body,
                    IsActive = true,
                    CreatedOnTimeUtc = DateTime.UtcNow,
                    UpdatedOnTimeUtc = DateTime.UtcNow,
                    DontSendBeforeDateUtc = emailModel.SendEmail.SendImmediately || !emailModel.SendEmail.DontSendBeforeDate.HasValue ?
                                        null : (DateTime?)_dateTimeHelper.ConvertToUtcTime(emailModel.SendEmail.DontSendBeforeDate.Value)
                };
                _queuedEmailService.InsertQueuedEmail(email);

                return SuccessJson(illegalWordsReplaced ? ApiResponseMessages.CustomEmailIllegalWordsReplaced : ApiResponseMessages.CustomEmailSendSuccess);
            }
            catch (PMSException pex)
            {
                return pex.LogLevel switch
                {
                    SystemLogLevel.Warning => WarnJson(pex.Message),
                    _ => ErrorJson(pex.Message)
                };
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }
        /// <summary>
        /// 用户角色分配API
        /// CustomerModelValidator对提交参数做不过滤处理，修改方法名时注意同步更改
        /// </summary>
        /// <param name="model">只使用其中Id: CustomerId, SelectedCustomerRoleIds</param>
        /// <returns></returns>
        [HttpPost(WebApiRouteConfig.BackendCustomerRoleAssign)]
        [AuthorizeCustomer(CustomerAuthorizeType.Admin)]
        public IActionResult CustomerAssginRoleApi([FromBody] CustomerModel model)
        {
            try
            {
                if (model == null || model.Id <= 0)
                    throw new PMSException(ApiResponseMessages.ArgumentCannotBeNull, SystemLogLevel.Error);
                if ((model.SelectedCustomerRoleIds?.Count ?? 0) <= 0)
                    throw new PMSException(ApiResponseMessages.NoCustomerRoleAssgined, SystemLogLevel.Warning);
                var customer = _customerService.GetCustomerById(model.Id);
                if (customer == null || customer.IsDeleted)
                    throw new PMSException(string.Format(ApiResponseMessages.EntityNotFound, "用户信息"), SystemLogLevel.Error);
                var availableRoles = _customerService.GetAllCustomerRoles(showHidden: true);
                //customer roles
                var currentCustomerRoleIds = _customerService.GetCustomerRoleIds(customer, true);
                CustomerModel curModel = _customerModelFactory.PrepareCustomerModel(null, customer);

                foreach (var customerRole in availableRoles)
                {
                    //ensure that the current customer cannot add/remove to/from "Administrators" system role
                    //if he's not an admin himself
                    if (_workContext.CurrentCustomer.Id == customer.Id &&
                        customerRole.RoleType == RoleType.Administrator &&
                        !_customerService.IsAdmin(_workContext.CurrentCustomer))
                        continue;
                    //ensure GuestRole cannot remove from customer's role list
                    //if he's already got
                    if (customerRole.RoleType == RoleType.Guests &&
                        customer.IsGuestUser(_customerService))
                        continue;

                    if (model.SelectedCustomerRoleIds.Contains(customerRole.Id))
                    {
                        //new role
                        if (currentCustomerRoleIds.All(roleId => roleId != customerRole.Id))
                        {
                            _customerService.AddCustomerRoleMapping(new CustomerCustomerRoleMapping { CustomerId = customer.Id, CustomerRoleId = customerRole.Id });
                            if (customerRole.RoleType == RoleType.Guests && curModel.AllowSendingOfWelcomeMessage)
                            {
                                _workflowMessageService.SendCustomerRegisteredWelcomeEmail(customer);
                            }
                        }
                    }
                    else
                    {
                        //prevent attempts to delete the administrator role from the user, if the user is the last active administrator
                        if (customerRole.RoleType == RoleType.Administrator && !SecondAdminAccountExists(customer))
                        {
                            throw new PMSException(ApiResponseMessages.AdminAccountShouldExistsFromDelete, SystemLogLevel.Warning);
                        }

                        //remove role
                        if (currentCustomerRoleIds.Any(roleId => roleId == customerRole.Id))
                            _customerService.RemoveCustomerRoleMapping(customer, customerRole);
                    }
                }
                return SuccessJson(ApiResponseMessages.CustomerRoleAssgined);

            }
            catch (PMSException pex)
            {
                return pex.LogLevel switch
                {
                    SystemLogLevel.Warning => WarnJson(pex.Message),
                    _ => ErrorJson(pex.Message)
                };
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }

        [AuthorizeCustomer(CustomerAuthorizeType.Admin)]
        [HttpPost(WebApiRouteConfig.BackendCustomerDelete)]
        public virtual IActionResult Delete([FromBody] BaseAuthModel deleteNode)
        {
            if (!_permissionService.AdminModuleButtonAuthorize(deleteNode.ModuleId, deleteNode.ButtonId))
                throw new PMSException(ApiResponseMessages.UnAuthorizedPermission, SystemLogLevel.Error);

            //try to get a customer with the specified id
            var customer = _customerService.GetCustomerById(deleteNode.Id);
            if (customer == null)
                throw new PMSException(string.Format(ApiResponseMessages.EntityNotFound, "用户信息"), SystemLogLevel.Error);

            try
            {
                //prevent user to delete himself
                if (customer.Id == _workContext.CurrentCustomer.Id)
                {
                    throw new PMSException(ApiResponseMessages.CustomerNotAllowedToDeleteHimself, SystemLogLevel.Warning);
                }
                //prevent attempts to delete the user, if it is the last active administrator
                if (_customerService.IsAdmin(customer) && !SecondAdminAccountExists(customer))
                {
                    throw new PMSException(ApiResponseMessages.AdminAccountShouldExistsFromDelete, SystemLogLevel.Warning);
                }

                //ensure that the current customer cannot delete "Administrators" if he's not an admin himself
                if (_customerService.IsAdmin(customer) && !_customerService.IsAdmin(_workContext.CurrentCustomer))
                {
                    throw new PMSException(ApiResponseMessages.OnlyAdminCanDeleteAdmin, SystemLogLevel.Warning);
                }

                //delete
                _customerService.DeleteCustomer(customer);

                //delete customer role mapping
                var curCustomerRoles = _customerService.GetCustomerRoles(customer, true);
                foreach (var role in curCustomerRoles)
                {
                    _customerService.RemoveCustomerRoleMapping(customer, role);
                }

                //delete customer associate attributes
                var customerAttributes = _genericAttributeService.GetAttributesForEntity(customer.Id, nameof(Customer));
                _genericAttributeService.DeleteAttributes(customerAttributes);

                //remove newsletter subscription (if exists)
                //foreach (var store in _storeService.GetAllStores())
                //{
                //    var subscription = _newsLetterSubscriptionService.GetNewsLetterSubscriptionByEmailAndStoreId(customer.Email, store.Id);
                //    if (subscription != null)
                //        _newsLetterSubscriptionService.DeleteNewsLetterSubscription(subscription);
                //}

                //activity log
                //_customerActivityService.InsertActivity("DeleteCustomer",
                //    string.Format(_localizationService.GetResource("ActivityLog.DeleteCustomer"), customer.Id), customer);

                return SuccessJson(ApiResponseMessages.CustomerDeleteSuccess);
            }
            catch (PMSException pex)
            {
                return pex.LogLevel switch
                {
                    SystemLogLevel.Warning => WarnJson(pex.Message),
                    _ => ErrorJson(pex.Message)
                };
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }

        #endregion

        #endregion

        #endregion
    }
}
